package com.qd.panda.service.card.collect;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.core.weixinmanager.domain.QrDTO;
import com.cdqidi.core.weixinmanager.model.MiddleUser;
import com.cdqidi.core.weixinmanager.service.wx.WxaApiService;
import com.cdqidi.core.weixinmanager.util.CallWxUtil;
import com.cdqidi.db.BaseService;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.dto.CacheKey;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.DateUtil;
import com.cdqidi.util.RedisTemplateUtil;
import com.cdqidi.util.SpringContextHolder;
import com.jfinal.springboot.weixin.annotation.ApiType;
import com.qd.common.panda.config.PandaParkConfigDTO;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.card.CardInfoDetailDTO;
import com.qd.common.panda.domain.entity.card.UserCardDTO;
import com.qd.common.panda.domain.entity.card.collect.CollectCardCoverDTO;
import com.qd.common.panda.domain.entity.card.collect.CollectCardDTO;
import com.qd.common.panda.domain.entity.card.collect.CollectCardRelationDTO;
import com.qd.common.panda.domain.entity.card.collect.ReceiveCardDTO;
import com.qd.common.panda.domain.entity.card.third.sync.ThirdPartyListDTO;
import com.qd.common.sys.domain.sendmsg.FusionMsg;
import com.qd.common.sys.domain.sendmsg.MsgReceiver;
import com.qd.common.sys.enums.BaseTableEnum;
import com.qd.panda.mapper.card.CollectCardMapper;
import com.qd.panda.model.*;
import com.qd.panda.service.card.CardInfoDetailService;
import com.qd.panda.service.card.CardInfoService;
import com.qd.panda.service.card.CardPlanService;
import com.qd.panda.service.card.UserCardService;
import com.qd.panda.service.card.third.sync.ThirdPartyListService;
import com.qd.system.service.dict.MbUtil;
import com.qd.system.service.msg.client.FusionMsgClientService;
import com.qd.system.util.FileConfirmUtil;
import com.qd.upload.constant.FileConfirmDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

/**
 * 领卷
 *
 * @author sjk
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class CollectCardService extends BaseService<CollectCardMapper, CollectCard> {

    private static final String PREFIX_ID = "panda_collect_card_cid_{0}";

    private final RedisTemplateUtil<CollectCard> redisTemplateUtil;
    private final CardPlanService cardPlanService;
    private final CardInfoService cardInfoService;
    private final CollectCardRelationService collectCardRelationService;
    private final CollectCardCoverService collectCardCoverService;
    private final CardInfoDetailService cardInfoDetailService;
    private final UserCardService userCardService;
    private final PandaParkConfigDTO pandaParkConfig;
    private final ThirdPartyListService thirdPartyListService;
    @Resource
    private WxaApiService wxaApiService;
    @Resource
    private FusionMsgClientService fusionMsgClientService;
    @Resource
    private PandaParkConfigDTO parkConfigDTO;

    /**
     * 保存
     *
     * @param dto 页面对象
     * @return 页面对象
     */
    @Transactional(rollbackFor = Exception.class)
    public CollectCardDTO save(CollectCardDTO dto) {
        dto.setCid(IdWorker.getIdStr());
        validator(dto, true);
        buildQrCode(dto);
        final CollectCard model = dtoToModel(dto);
        try {
            if (super.save(model)) {
                return modelToDto(model);
            }
            throw new ApiException("添加失败");
        } finally {
            clearCache(model);
            model.freeData();
        }
    }

    /**
     * 修改
     *
     * @param dto 页面对象
     * @return 页面对象
     */
    @Transactional(rollbackFor = Exception.class)
    public CollectCardDTO update(CollectCardDTO dto) {
        final CollectCard historyModel = Optional.ofNullable(getById(dto.getCid())).orElseThrow(() -> new ApiException("ID不存在,不能更新"));
        if (!StringUtils.hasLength(historyModel.getQrCode())) {
            buildQrCode(dto);
        }
        validator(dto, false);
        final CollectCard model = dtoToModel(dto);
        try {
            if (super.updateById(model)) {
                return modelToDto(model);
            }
            throw new ApiException("更新失败");
        } finally {
            clearCache(historyModel);
            historyModel.freeData();
            model.freeData();
        }
    }

    /**
     * 删除，单个
     *
     * @param cid 主键
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeById(String cid) {
        final CollectCard historyModel = Optional.ofNullable(getById(cid)).orElseThrow(() -> new ApiException("数据不存在,不能删除"));
        try {
            collectCardRelationService.removeByCid(cid);
            if (!super.removeById(cid)) {
                throw new ApiException("删除失败");
            }
        } finally {
            clearCache(historyModel);
            historyModel.freeData();
        }
    }

    /**
     * 批量删除
     *
     * @param ids 主键集合
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeBatchIds(List<String> ids) {
        ids.forEach(this::removeById);
    }

    /**
     * 根据传入对象构建查询参数，判断是否存在
     *
     * @param dto 参数
     * @return 存在为true
     */
    @Transactional(readOnly = true)
    public Boolean isExists(CollectCardDTO dto) {
        final QueryWrapper<CollectCard> queryWrapper = createQueryWrapper(dto);
        final boolean exists = super.count(queryWrapper) > 0;
        queryWrapper.clear();
        return exists;
    }

    /**
     * 根据主键判断数据是否存在
     *
     * @param cid 主键
     * @return 存在为true
     */
    @Transactional(readOnly = true)
    public Boolean isExistsById(String cid) {
        boolean exists = false;
        if (StringUtils.hasLength(cid)) {
            final CollectCard model = getById(cid);
            exists = (null != model);
            if (exists) {
                model.freeData();
            }
        }
        return exists;
    }

    /**
     * 根据主键获取数据
     *
     * @param cid 主键
     * @return 单条记录
     */
    public CollectCard getById(String cid) {
        final String key = RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, cid);
        return redisTemplateUtil.get(new CacheKey().setKey(key).setTimeout(ConstantDto.REDIS_TIME_OUT_DAY), () -> super.getById(cid), CollectCard.class);
    }

    /**
     * 根据主键获取数据
     *
     * @param cid 主键
     * @return 单条记录，转换成页面对象
     */
    @Transactional(readOnly = true)
    public CollectCardDTO getByIdDto(String cid) {
        return Optional.ofNullable(getById(cid)).map(this::modelToDto).orElse(null);
    }

    /**
     * 根据条件查询单条数据
     *
     * @param dto 查询参数
     * @return 单条记录
     */
    public CollectCard getOne(CollectCardDTO dto) {
        final QueryWrapper<CollectCard> queryWrapper = createQueryWrapper(dto);
        CollectCard model = super.getOne(queryWrapper);
        queryWrapper.clear();
        return model;
    }

    /**
     * 根据条件查询单条数据
     *
     * @param dto 查询参数
     * @return 单条记录，转换成页面对象
     */
    @Transactional(readOnly = true)
    public CollectCardDTO getOneDto(CollectCardDTO dto) {
        return Optional.ofNullable(getOne(dto)).map(this::modelToDto).orElse(null);
    }

    /**
     * 根据条件查询列表数据
     *
     * @param dto 查询参数
     * @return 列表数据
     */
    public List<CollectCard> getList(CollectCardDTO dto) {
        final QueryWrapper<CollectCard> queryWrapper = createQueryWrapper(dto);
        final List<CollectCard> list = super.list(queryWrapper);
        queryWrapper.clear();
        return list;
    }

    /**
     * 根据条件查询列表数据
     *
     * @param dto 查询参数
     * @return 列表数据，转换成页面对象
     */
    @Transactional(readOnly = true)
    public List<CollectCardDTO> getListDto(CollectCardDTO dto) {
        return modelToDtoList(getList(dto));
    }

    /**
     * 分页数据
     *
     * @param page 分页对象
     * @param dto  查询参数
     * @return 分页信息
     */
    @Transactional(readOnly = true)
    public IPage<CollectCardDTO> page(Page<CollectCard> page, CollectCardDTO dto) {
        final QueryWrapper<CollectCard> queryWrapper = createQueryWrapper(dto, "t1.");
        final IPage<CollectCardDTO> iPage = baseMapper.page(page, queryWrapper);
        Optional.ofNullable(iPage.getRecords()).ifPresent(l -> l.forEach(this::buildDisplay));
        queryWrapper.clear();
        return iPage;
    }

    /**
     * 清空缓存
     *
     * @param model 数据库对象
     */
    public void clearCache(CollectCard model) {
        if (null == model) {
            return;
        }
        redisTemplateUtil.deleteByKey(RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, model.getCid()));
    }

    /**
     * 批量清空缓存
     *
     * @param list 数据库对象
     */
    public void clearCaches(List<CollectCard> list) {
        if (null == list || list.isEmpty()) {
            return;
        }
        List<String> ids = list.stream().map(model -> RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, model.getCid())).collect(toList());
        if (!ids.isEmpty()) {
            redisTemplateUtil.deleteByKey(ids);
            ids.clear();
        }
    }

    /**
     * 数据库对象转页面对象
     *
     * @param model 数据库对象
     * @return 页面对象
     */
    public CollectCardDTO modelToDto(CollectCard model) {
        if (null == model) {
            return null;
        }
        final CollectCardDTO dto = new CollectCardDTO();
        dto.setCid(model.getCid());
        dto.setName(model.getName());
        dto.setNote(model.getNote());
        dto.setAddTime(model.getAddTime());
        dto.setUpdateTime(model.getUpdateTime());
        dto.setPlanId(model.getPlanId());
        dto.setPromotionCode(model.getPromotionCode());
        dto.setQrCode(model.getQrCode());
        dto.setAvailableQuantity(model.getAvailableQuantity());
        dto.setAllocatedQuantity(model.getAllocatedQuantity());
        buildDisplay(dto);
        return dto;
    }

    /**
     * 页面对象转数据库对象
     *
     * @param dto 页面对象
     * @return 数据库对象
     */
    public CollectCard dtoToModel(CollectCardDTO dto) {
        if (null == dto) {
            return null;
        }
        final CollectCard model = new CollectCard();
        model.setCid(dto.getCid());
        model.setName(dto.getName());
        model.setNote(dto.getNote());
        model.setAddTime(dto.getAddTime());
        model.setUpdateTime(dto.getUpdateTime());
        model.setPlanId(dto.getPlanId());
        model.setPromotionCode(dto.getPromotionCode());
        model.setQrCode(dto.getQrCode());
        model.setAvailableQuantity(dto.getAvailableQuantity());
        model.setAllocatedQuantity(dto.getAllocatedQuantity());
        return model;
    }

    /**
     * 码表转换
     *
     * @param dto 页面对象
     */
    public void buildDisplay(CollectCardDTO dto) {
        CardPlan cardPlan = cardPlanService.getById(dto.getPlanId());
        if (null != cardPlan) {
            if (DateUtil.nowLocalDate().isBefore(cardPlan.getUseStartTime())) {
                dto.setState(1);
            } else if (DateUtil.nowLocalDate().isAfter(cardPlan.getUseEndTime())) {
                dto.setState(2);
            } else if (null == dto.getAvailableQuantity()) {
                log.info("没有可以领取的卷,cid: {},码数量: {},码可用数量: {}", dto.getCid(), dto.getAllocatedQuantity(), null);
                dto.setState(3);
            } else if (dto.getAvailableQuantity() == -1 && dto.getAllocatedQuantity() == -1) {
                //无限量券
                dto.setState(0);
            } else if (dto.getAvailableQuantity() < 1) {
                log.info("没有可以领取的卷,cid: {},码数量: {},码可用数量: {}", dto.getCid(), dto.getAllocatedQuantity(), dto.getAvailableQuantity());
                dto.setState(3);
            } else {
                dto.setState(0);
            }
            dto.setPlanIdDisplay(cardPlan.getPlanName());
            dto.setRebate(cardPlan.getRebate());
            dto.setInfiniteQuantity(cardPlan.getInfiniteQuantity());
        }
        dto.setPromotionCodeDisplay(MbUtil.idToDisplay(dto.getPromotionCode()));
        Optional.ofNullable(dto.getQrCode()).ifPresent(qrCode -> {
            String qrCodePath = FileConfirmUtil.getFilePath(qrCode, dto.getCid() + ".jpg");
            dto.setQrCode(qrCodePath);
        });
        Optional.ofNullable(collectCardCoverService.getByIdDto(dto.getCid())).ifPresent(dto::setCover);
    }

    /**
     * 数据库对象转页面对象
     *
     * @param list 数据库对象
     * @return 页面对象
     */
    public List<CollectCardDTO> modelToDtoList(List<CollectCard> list) {
        return Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(this::modelToDto).collect(toList());
    }

    /**
     * 页面对象转数据库对象
     *
     * @param list 页面对象
     * @return 数据库对象
     */
    public List<CollectCard> dtoToModelList(List<CollectCardDTO> list) {
        return Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(this::dtoToModel).collect(toList());
    }

    /**
     * 拼装查询参数，除了主键的其他字段会自动加入进来
     *
     * @param dto 查询参数，不为空的属性会被自动加入
     */
    public QueryWrapper<CollectCard> createQueryWrapper(CollectCardDTO dto) {
        return createQueryWrapper(dto, "");
    }

    /**
     * 拼装查询参数，除了主键的其他字段会自动加入进来
     *
     * @param dto        查询参数，不为空的属性会被自动加入
     * @param tableAlias 表别名
     */
    public QueryWrapper<CollectCard> createQueryWrapper(CollectCardDTO dto, String tableAlias) {
        final QueryWrapper<CollectCard> queryWrapper = new QueryWrapper<>();
        if (null != dto) {
            if (StringUtils.hasLength(tableAlias) && tableAlias.charAt(tableAlias.length() - 1) != '.') {
                tableAlias += ".";
            }
            if (StringUtils.hasLength(dto.getName())) {
                queryWrapper.like(tableAlias + "name", dto.getName());
            }
            if (StringUtils.hasLength(dto.getPlanId())) {
                queryWrapper.eq(tableAlias + "plan_id", dto.getPlanId());
            }
            if (StringUtils.hasLength(dto.getPromotionCode())) {
                queryWrapper.eq(tableAlias + "promotion_code", dto.getPromotionCode());
            }
        }
        queryWrapper.orderByDesc("add_time");
        queryWrapper.orderByAsc("promotion_code");
        return queryWrapper;
    }

    /**
     * 批量检查主键在数据库中是否存在
     *
     * @param ids 主键集合
     * @return 主键查询出来的集合
     */
    public List<CollectCard> checkIds(List<String> ids) {
        if (null == ids || ids.isEmpty()) {
            throw new ApiException("ids不能为空");
        }
        final List<CollectCard> list = super.listByIds(ids);
        if (list.isEmpty()) {
            throw new ApiException("ids不存在" + Arrays.toString(ids.toArray()));
        }
        if (ids.size() == list.size()) {
            return list;
        }
        List<String> dbIds = list.stream().map(CollectCard::getCid).collect(toList());
        final List<String> notExistsList = ids.stream().filter(id -> !dbIds.contains(id)).collect(toList());
        dbIds.clear();
        if (!notExistsList.isEmpty()) {
            throw new ApiException("ids不存在" + Arrays.toString(notExistsList.toArray()));
        }
        return list;
    }

    private void validator(CollectCardDTO dto, boolean isAdd) {
        if (MbUtil.isNotExists(dto.getPromotionCode(), BaseTableEnum.PROMOTION_CODE)) {
            throw new ApiException("推广码值错误");
        }
        CardPlan cardPlan = cardPlanService.getById(dto.getPlanId());
        if (null == cardPlan) {
            throw new ApiException("计划ID值错误");
        }
        if (isAdd) {
            dto.setAllocatedQuantity(cardPlan.getAllocatedQuantity());
            dto.setAvailableQuantity(cardPlan.getAllocatedQuantity());
        }
        List<CardInfo> list = cardInfoService.getListByPlanId(dto.getPlanId());
        if (list.isEmpty()) {
            throw new ApiException("计划信息异常");
        }
        if(isAdd){
            List<CollectCardRelation> addList = list.stream().map(cardInfo -> {
                CollectCardRelation cardRelation = new CollectCardRelation();
                cardRelation.setCardMsgId(cardInfo.getCardMsgId());
                if(null !=cardPlan.getAllocatedQuantity()){
                    if (cardPlan.getAllocatedQuantity() == -1) {
                        cardRelation.setCardQuantity(cardPlan.getAllocatedQuantity());
                    } else {
                        cardRelation.setCardQuantity(cardInfo.getCardQuantity() * cardPlan.getAllocatedQuantity());
                    }
                }
                if(null != dto.getAvailableQuantity()){
                    if (dto.getAvailableQuantity() == -1) {
                        cardRelation.setAvailableQuantity(dto.getAvailableQuantity());
                    } else {
                        cardRelation.setAvailableQuantity(cardRelation.getCardQuantity());
                    }
                }
                cardRelation.setCid(dto.getCid());
                cardRelation.setPromotionCode(dto.getPromotionCode());
                return cardRelation;
            }).collect(toList());
            collectCardRelationService.saveBatch(addList);
            addList.clear();
        }
        CollectCardCoverDTO cover = dto.getCover();
        if (null != cover) {
            cover.setCid(dto.getCid());
            if (StringUtils.hasLength(cover.getPic())) {
                if (cover.getPic().startsWith(ConstantDto.HTTPS) || cover.getPic().startsWith(ConstantDto.HTTP)) {
                    cover.setPic(null);
                } else {
                    FileConfirmDTO fileConfirmDto = FileConfirmUtil.singleFileConfirm(cover.getPic(), ConstantDto.ATTACHMENTTYPE_2);
                    if (null == fileConfirmDto) {
                        throw new ApiException("文件ID不存在[" + cover.getPic() + "]");
                    }
                    cover.setPic(fileConfirmDto.getOfficialFile());
                }
            }
            if (StringUtils.hasLength(cover.getMiddlePic())) {
                if (cover.getMiddlePic().startsWith(ConstantDto.HTTPS) || cover.getMiddlePic().startsWith(ConstantDto.HTTP)) {
                    cover.setMiddlePic(null);
                } else {
                    FileConfirmDTO fileConfirmDto = FileConfirmUtil.singleFileConfirm(cover.getMiddlePic(), ConstantDto.ATTACHMENTTYPE_2);
                    if (null == fileConfirmDto) {
                        throw new ApiException("文件ID不存在[" + cover.getMiddlePic() + "]");
                    }
                    cover.setMiddlePic(fileConfirmDto.getOfficialFile());
                }
            }
            if (StringUtils.hasLength(cover.getDownPic())) {
                if (cover.getDownPic().startsWith(ConstantDto.HTTPS) || cover.getDownPic().startsWith(ConstantDto.HTTP)) {
                    cover.setDownPic(null);
                } else {
                    FileConfirmDTO fileConfirmDto = FileConfirmUtil.singleFileConfirm(cover.getDownPic(), ConstantDto.ATTACHMENTTYPE_2);
                    if (null == fileConfirmDto) {
                        throw new ApiException("文件ID不存在[" + cover.getDownPic() + "]");
                    }
                    cover.setDownPic(fileConfirmDto.getOfficialFile());
                }
            }
            if (Boolean.TRUE.equals(collectCardCoverService.isExistsById(dto.getCid()))) {
                collectCardCoverService.update(cover);
            } else {
                collectCardCoverService.save(cover);
            }
            cover.freeData();
        }
    }


    @Transactional(rollbackFor = Exception.class)
    public void receiveCard(String userId, String mobile, ReceiveCardDTO dto, CollectCardRelationDTO collectCardRelationDTO) {
        collectCardRelationService.update(collectCardRelationDTO);
        CardInfoDetailDTO cardInfoDetailDTO = buildCardInfoDetail(userId, mobile, dto);
        cardInfoDetailDTO.freeData();
    }

    public CardInfoDetailDTO buildCardInfoDetail(String userId, String mobile, ReceiveCardDTO dto) {
        CardInfoDetailDTO cardInfoDetailDTO = updateCardInfoDetail(userId, mobile, dto.getPlanId(), dto.getCardMsgId());
        saveUserCard(userId, cardInfoDetailDTO,ConstantDto.SF0);
        if (StringUtils.hasLength(Optional.ofNullable(cardPlanService.getById(dto.getPlanId())).map(CardPlan::getThirdParty).orElse(""))) {
            updateThirdPartyList(cardInfoDetailDTO);
        }
        return cardInfoDetailDTO;
    }

    public void automatic(String userId, String mobile, ReceiveCardDTO dto, MiddleUser middleUser) {
        CardInfoDetailDTO cardInfoDetailDTO = addCardInfoDetail(userId, mobile, dto.getPlanId(), dto.getCardMsgId());
        saveUserCard(userId, cardInfoDetailDTO,ConstantDto.SF0);
        if (null != middleUser) {
            //生成一张卡券给分享人
            createCard(dto,middleUser);
        }
    }

    private void createCard(ReceiveCardDTO dto, MiddleUser middleUser) {
        CardInfoDetailDTO cardInfoDetailDTO = addCardInfoDetail(middleUser.getUserId(), middleUser.getMobile(), dto.getPlanId(), dto.getCardMsgId());
        saveUserCard(middleUser.getUserId(), cardInfoDetailDTO,ConstantDto.SF1);
    }

    private void updateThirdPartyList(CardInfoDetailDTO cardInfoDetailDTO) {
        ThirdPartyListDTO thirdPartyListDTO = thirdPartyListService.getListByCardIdDto(cardInfoDetailDTO.getCardId());
        if (null != thirdPartyListDTO) {
            thirdPartyListDTO.setState(PandaConstant.USE_STATE_1);
            thirdPartyListDTO.setRedemptionTime(cardInfoDetailDTO.getRedemptionTime());
            thirdPartyListService.update(thirdPartyListDTO);
            thirdPartyListDTO.freeData();
        }
    }

    private CardInfoDetailDTO updateCardInfoDetail(String userId, String mobile, String planId, String cardMsgId) {
        LocalDateTime now = LocalDateTime.now();
        LocalDate currentDate = now.toLocalDate();
        CardInfoDetail cardInfoDetail = cardInfoDetailService.getOneByCardMsgId(planId, cardMsgId);
        if (null == cardInfoDetail) {
            log.info("没有多余的劵,planId: {},cardMsgId: {}", planId, cardMsgId);
            throw new ApiException(10005, "没有多余的券");
        }
        CardInfo cardInfo = cardInfoService.getById(cardMsgId);
        cardInfoDetail.setValidityEndTime(currentDate.plusDays(cardInfo.getVolumeValidity()));
        cardInfoDetail.setMobile(mobile);
        cardInfoDetail.setUserId(userId);
        cardInfoDetail.setRedemptionTime(now);
        cardInfoDetail.setUseState(PandaConstant.USE_STATE_1);
        CardInfoDetailDTO cardInfoDetailDTO = cardInfoDetailService.modelToDto(cardInfoDetail);
        cardInfoDetailService.update(cardInfoDetailDTO);
        return cardInfoDetailDTO;
    }

    private CardInfoDetailDTO addCardInfoDetail(String userId, String mobile, String planId, String cardMsgId) {
        LocalDateTime now = LocalDateTime.now();
        LocalDate currentDate = now.toLocalDate();
        CardInfoDetailDTO cardInfoDetailDTO = new CardInfoDetailDTO();
        CardInfo cardInfo = cardInfoService.getById(cardMsgId);
        cardInfoDetailDTO.setCardId(IdWorker.getIdStr());
        cardInfoDetailDTO.setMobile(mobile);
        cardInfoDetailDTO.setRedemptionTime(now);
        cardInfoDetailDTO.setValidityEndTime(currentDate.plusDays(cardInfo.getVolumeValidity()));
        cardInfoDetailDTO.setUseState(PandaConstant.USE_STATE_1);
        cardInfoDetailDTO.setPlanId(planId);
        cardInfoDetailDTO.setCardMsgId(cardMsgId);
        cardInfoDetailDTO.setUserId(userId);
        cardInfoDetailService.save(cardInfoDetailDTO);
        return cardInfoDetailDTO;
    }

    public void saveUserCard(String userId, CardInfoDetailDTO cardInfoDetail,String systemDistribution) {
        UserCardDTO userCard = new UserCardDTO();
        userCard.setValidityEndTime(cardInfoDetail.getValidityEndTime());
        userCard.setState(PandaConstant.USE_STATE_1);
        userCard.setUserId(userId);
        userCard.setCardMsgId(cardInfoDetail.getCardMsgId());
        userCard.setCardId(cardInfoDetail.getCardId());
        userCard.setRedemptionTime(cardInfoDetail.getRedemptionTime());
        userCard.setSystemDistribution(systemDistribution);
        userCardService.save(userCard);
    }

    public void buildQrCode(CollectCardDTO dto) {
        final String activeProfile = SpringContextHolder.getActiveProfile();
        final String appId = pandaParkConfig.getDefaultMiniProgramAppId();
        if (!StringUtils.hasLength(appId)) {
            throw new ApiException("默认小程序ID不能为空，生成葵花码异常");
        }
        CallWxUtil.callInterface(appId, ApiType.WXA, () -> {
            QrDTO qrDTO = new QrDTO();
            ApiResultWrapper<Object> resultWrapper;
            if (activeProfile.equals(SpringContextHolder.PROFILE_OFFICIAL)) {
                //正式环境
                qrDTO.setScene("cid=" + dto.getCid())
                        .setName(dto.getCid())
                        .setAutoColor(true)
                        .setIsHyAline(false)
                        .setPage("pages/social-coupons/social-coupons");
                resultWrapper = wxaApiService.getUnlimited(qrDTO);
            } else {
                qrDTO.setScene("cid=" + dto.getCid())
                        .setName(dto.getCid())
                        .setAutoColor(true)
                        .setIsHyAline(false)
                        .setPath("pages/social-coupons/social-coupons");
                resultWrapper = wxaApiService.getQrCode(qrDTO);
            }
            if (resultWrapper.isSuccess()) {
                log.info(resultWrapper.getData().toString());
                dto.setQrCode(resultWrapper.getData().toString());
            } else {
                throw new ApiException(resultWrapper.getMsg());
            }
            return null;
        });
    }

    @Transactional(readOnly = true)
    public CollectCardDTO getByPromotionCode(String promotionCode) {
        QueryWrapper<CollectCard> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("promotion_code", promotionCode);
        queryWrapper.last("limit 1");
        queryWrapper.orderByDesc("add_time", "update_time");
        CollectCard collectCard = baseMapper.selectOne(queryWrapper, false);
        queryWrapper.clear();
        return modelToDto(collectCard);
    }

    @Transactional(readOnly = true)
    public boolean existsByPlanId(String planId) {
        QueryWrapper<CollectCard> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("plan_id", planId);
        final boolean exists = SqlHelper.retBool(super.count(queryWrapper));
        queryWrapper.clear();
        return exists;
    }

    public void sendTemplateMessage(String bid, String userId) {
        MsgReceiver receiver = new MsgReceiver();
        //人
        receiver.setId(userId);
        //接收者类型
        receiver.setClassify(MsgReceiver.CLASSIFY_USER);
        receiver.getProperties().addProp("thing1", "“熊猫泊车”优惠券");
        receiver.getProperties().addProp("thing4", "好友邀请成功，卡券已到账。立即点击查看。");
        fusionMsgClientService.sendMsg(parkConfigDTO.getDefaultMiniProgramAppId(), "/pages/coupons/coupons", PandaConstant.T_1005, userId, bid, "卡券到账通知", PandaConstant.MSG_EVENT_MSG_CLASSIFY_1, receiver, FusionMsg.SEND_FLAG_WEIXIN);
    }

}